#include "Thread.h"
#include "AbstractEventQueue.h"

enum {
	msgQuit = -1,
	msgSetThreadName = -2,
};

AbstractEventQueue::AbstractEventQueue(bool start)
{
	init();
	if(start)
		Start();
}

AbstractEventQueue::~AbstractEventQueue(void)
{
	Stop();
	pthread_mutex_lock(m_mutex);
	tEventList::iterator Iter = m_eventList->begin();
	while(Iter != m_eventList->end())
	{
		//SAFE_DELETE((tEvent*)*Iter);
		tEvent* event = *Iter;
		delete event;
		Iter++;
	}
	pthread_mutex_unlock(m_mutex);
	SAFE_DELETE(m_eventList);

	pthread_cond_signal(m_cond);
	pthread_cond_destroy(m_cond);
	SAFE_DELETE(m_cond);
	pthread_mutex_destroy(m_waitMutex);
	pthread_mutex_destroy(m_mutex);
	SAFE_DELETE(m_waitMutex);
	SAFE_DELETE(m_mutex);
}

bool AbstractEventQueue::Stop(bool waitQuit)
{
	PostEvent(msgQuit);
	AbstractThread::Stop();
	return true;
}

void AbstractEventQueue::init()
{
	m_eventList = new tEventList;

	m_mutex = new pthread_mutex_t;
	m_waitMutex = new pthread_mutex_t;
	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_init(m_mutex, &attr);
	pthread_mutex_init(m_waitMutex, &attr);
	pthread_mutexattr_destroy(&attr);

	m_cond = new pthread_cond_t;
	pthread_cond_init(m_cond, NULL);
}

void AbstractEventQueue::SendEvent(MsgID id, void* lParam, void* wParam)
{
	pthread_cond_t cond;
	pthread_mutex_t mutex;
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	tEvent* event = new tEvent;
	event->id = id;
	event->lParam = lParam;
	event->wParam = wParam;
	event->cond = &cond;
	pthread_mutex_lock(&mutex);
	PostEvent(event);

	pthread_cond_wait(&cond, &mutex);
	pthread_cond_destroy(&cond);
	pthread_mutex_unlock(&mutex);
	pthread_mutex_destroy(&mutex);
}

void AbstractEventQueue::PostEvent(MsgID id, void *lParam, void *wParam)
{
	tEvent* event = new tEvent;
	event->id = id;
	event->lParam = lParam;
	event->wParam = wParam;
	event->cond = NULL;
	PostEvent(event);
}

void AbstractEventQueue::SetThreadName(char* name)
{
	if(name == NULL)
		return;
	char* threadName = strdup(name);
	PostEvent(msgSetThreadName, threadName);
}

void AbstractEventQueue::PostEvent(tEvent* event)
{
	pthread_mutex_lock(m_mutex);
	m_eventList->push_back(event);
	pthread_mutex_unlock(m_mutex);
	pthread_cond_signal(m_cond);
}

bool AbstractEventQueue::HasEvent()
{
	bool empty = false;
	pthread_mutex_lock(m_mutex);
	empty = m_eventList->empty();
	pthread_mutex_unlock(m_mutex);
	return !empty;
}

void AbstractEventQueue::DoAction()
{
	while(true)
	{
		AbstractEventQueue::TestCancel();
		
		tEvent* event = NULL;
		pthread_mutex_lock(m_mutex);
		if(!m_eventList->empty())
		{
			event = m_eventList->front();
			m_eventList->pop_front();
		}
		pthread_mutex_unlock(m_mutex);
		if(event == NULL)
		{
			pthread_mutex_lock(m_waitMutex);
			pthread_cond_wait(m_cond, m_waitMutex);
			pthread_mutex_unlock(m_waitMutex);
#ifdef _WINDOWS
			Sleep(1);
#endif
			continue;
		}

		bool needQuit = false;
		if(event->id == msgQuit)
			needQuit = true;
		else if(event->id == msgSetThreadName)
		{
			AbstractThread::SetThreadName((char*)event->lParam);
			free(event->lParam);
		}
		else
			ProcessEvent(event->id, event->lParam, event->wParam);

		if(event->cond != NULL)
			pthread_cond_signal(event->cond);
			
		SAFE_DELETE(event);
		AbstractThread::TestCancel();
		if(needQuit)
			break;
	}
}

void AbstractEventQueue::CleanUp()
{
	AbstractThread::CleanUp();
}
